/*
* Copyright (c) 2007 by Kirill Kolodyazhniy.
* See the file "license.terms" for information on usage and redistribution.
*/

#ifndef M_PHYSICSYSTEM_H
#define M_PHYSICSYSTEM_H

#include "factory.h"
#include "types.h"
#include "common.h"
#include "vector3.h"
#include "refptr.h"

#include "space.h"
#include "solid.h"

#include <map>
#include <string>

namespace Engine
{
	/**
	*   Abstract class which implement public interface to physic systems.
	*/
	class PhysicSystem
	{
	public:
		typedef std::map<std::string, RefPtr<Space, WeakPtrExtension> > SpaceMap;
		typedef std::map<std::string, RefPtr<Solid, WeakPtrExtension> > SolidMap;

		/**
		*   Constructor.
		*/
		PhysicSystem(const std::string& name):m_step(0.0167), m_name(name){}

		/**
		*   Destructor.
		*/
		virtual ~PhysicSystem();

		/**
		*   Return name.
		*/
		const std::string& GetName()const{return m_name;}

		/**
		*   Set system gravity
		*/
		void SetGravity(const Vector3<REAL>& vec){SetGravity(vec.x, vec.y, vec.z);}

		/**
		*   Set system gravity
		*/
		virtual void SetGravity(REAL x, REAL y, REAL z) = 0;

		/**
		*   Delete all objects associated with this system.
		*/
		void DeleteAll();

		/**
		*   Update object positions, collide, ...
		*/
		void Update();

		/**
 		*    Set simulation step size
		*/
		void SetStepSize(REAL step);

		/**
		*   Create new space for optimize collisions.
		*/
		SpacePtr CreateSpace(const std::string& name);

		/**
		*   Create solid.
		*/
		SolidPtr CreateSolid(const std::string& name);

		/**
		*   Set parent scene node to all bodies
		*/
		void SetRootSceneNode(SceneNodePtr node);

	protected:

		SceneNodePtr m_rootNode;

	private:

		/**
		*   Create specific to implementation space.
		*/
		virtual Space* CreateSpaceImpl(const std::string& name) = 0;

		/**
		*   Create solid implementation.
		*/
		virtual Solid* CreateSolidImpl(const std::string& name) = 0;

		/**
		*   Make real simulation.
		*/
		virtual void Simulate(REAL step) = 0;

	private:

		REAL m_step;

		std::string m_name;

		SpaceMap m_spaces;
		SolidMap m_solids;
	};

	/**
	*   Factory for creating physic systems objects.
	*/
	class PhysicSystemFactory: public Factory<PhysicSystem>
	{
	};
}

#endif
